package hu.mapro.gwtui.gxt.client.columnmodel;


import java.util.Arrays;
import java.util.List;
import java.util.Map;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sencha.gxt.core.client.ValueProvider;
import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
import com.sencha.gxt.widget.core.client.grid.ColumnModel;

public class Builder<T, RO, RW> implements ColumnModelProvider<T> {
	
	ReadOnlyInterface<T, RO> readOnlyOperations;
	ReadWriteInterface<T, RW> readWriteOperations;
	
	public Builder(
			ReadOnlyInterface<T, RO> readOnlyOperations,
			ReadWriteInterface<T, RW> readWriteOperations) {
		super();
		this.readOnlyOperations = readOnlyOperations;
		this.readWriteOperations = readWriteOperations;
	}


	List<ColumnConfig<T, ?>> columns = Lists.newArrayList();
	Map<RO, ColumnConfig<T, ?>> readOnlyMap = Maps.newHashMap();
	Map<RW, ColumnConfig<T, ?>> readWriteMap = Maps.newHashMap();

	public void readOnly(RO[] fields) {
		readOnly(Arrays.asList(fields));
	}
	public void readOnly(Iterable<RO>fields) {
		for (RO f : fields) {
			readOnly(f);
		}
	}
	public <V> ColumnConfig<T, V> readOnly(final RO field) {
		@SuppressWarnings("unchecked")
		ColumnConfig<T, V> cc = (ColumnConfig<T, V>) readOnlyMap.get(field);
		
		if (cc==null) {
			cc = new ColumnConfig<T, V>(new ValueProvider<T, V>() {

				@Override
				public V getValue(T object) {
					return readOnlyOperations.getValue(field, object);
				}

				@Override
				public void setValue(T object, V value) {
					throw new UnsupportedOperationException("setValue not implemented for columns");
				}

				@Override
				public String getPath() {
					return readOnlyOperations.getPath(field);
				}
				
			});
			addReadOnlyField(field, cc);
		}
		
		return cc;
	}
	private <V> void addReadOnlyField(final RO field, ColumnConfig<T, V> cc) {
		readOnlyMap.put(field, cc);
		cc.setHeader(readOnlyOperations.getLabel(field));
		columns.add(cc);
	}


	
	public void readWrite(RW[] fields) {
		readWrite(Arrays.asList(fields));
	}
	public void readWrite(Iterable<RW>fields) {
		for (RW f : fields) {
			readWrite(f);
		}
	}
	public <V> ColumnConfig<T, V> readWrite(final RW field) {
		@SuppressWarnings("unchecked")
		ColumnConfig<T, V> cc = (ColumnConfig<T, V>) readWriteMap.get(field);
		
		if (cc==null) {
			cc = new ColumnConfig<T, V>(new ValueProvider<T, V>() {

				@Override
				public V getValue(T object) {
					return readWriteOperations.getValue(field, object);
				}

				@Override
				public void setValue(T object, V value) {
					readWriteOperations.setValue(field, object, value);
				}

				@Override
				public String getPath() {
					return readWriteOperations.getPath(field);
				}
				
			});
			addReadWriteField(field, cc);
		}
		
		return cc;
	}
	private <V> void addReadWriteField(final RW field, ColumnConfig<T, V> cc) {
		readWriteMap.put(field, cc);
		cc.setHeader(readWriteOperations.getLabel(field));
		columns.add(cc);
	}
	
	
	
	public ColumnModel<T> asColumnModel() {
		return new ColumnModel<T>(columns);
	}
	
}
